package com.x2.modular.system.controller;

import cn.hutool.json.JSONUtil;
import com.x2.core.base.controller.BaseController;
import com.x2.core.util.StringUtil;
import com.x2.core.util.ToolUtil;
import com.x2.kernel.model.exception.ServiceException;
import com.x2.kernel.model.exception.enums.CoreExceptionEnum;
import com.x2.kernel.model.response.ResponseData;
import com.x2.modular.system.entity.FileInfo;
import com.x2.modular.system.model.UploadResult;
import com.x2.modular.system.model.result.SysFileBusinessResult;
import com.x2.modular.system.service.FileInfoService;
import com.x2.modular.system.service.SysFileBusinessService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 附件业务关系控制器
 *
 * @author changpeng
 * @date 2021-02-03 14:06:59
 */
@Controller
@RequestMapping("/sys/file")
public class SysFileBusinessController extends BaseController {

    private final static String URL_PREFIX = "/modular/system/file";

    private SysFileBusinessService sysFileBusinessService;
    private FileInfoService fileInfoService;

    @Autowired
    public SysFileBusinessController(SysFileBusinessService sysFileBusinessService, FileInfoService fileInfoService) {
        this.sysFileBusinessService = sysFileBusinessService;
        this.fileInfoService = fileInfoService;
    }

    @RequestMapping("/demo")
    public String demo() {
        return URL_PREFIX + "/uploadFileDemo.html";
    }

    @RequestMapping(path = "/upload", method = RequestMethod.POST)
    @ResponseBody
    public ResponseData upload(@RequestPart("file") MultipartFile file) {
        UploadResult uploadResult = this.fileInfoService.uploadFile(file);
        return ResponseData.success(0, "上传成功", SysFileBusinessResult.createUploadResult(uploadResult.getFileId(), uploadResult.getOriginalFilename(), uploadResult.getFileSize(), uploadResult.getFileSuffix()));
    }

    /**
     * 根据附件id进行预览
     *
     * @param fileId: 附件id
     * @return 图片流
     */
    @RequestMapping("/{fileId}.image")
    @ResponseBody
    public Object previewImage(@PathVariable String fileId, HttpServletResponse response) {
        try {
            response.setContentType("image/jpeg");
            response.getOutputStream().write(this.fileInfoService.previewImage(fileId));
        } catch (IOException e) {
            throw new ServiceException(CoreExceptionEnum.SERVICE_ERROR);
        }
        return null;
    }

    /**
     * 根据附件id进行预览
     *
     * @param fileId: 附件id
     * @return 图片流
     */
    @RequestMapping("/{fileId}.{fileSuffix}")
    @ResponseBody
    public Object aaa(@PathVariable String fileId, HttpServletResponse response) {
        try {
            response.setContentType("image/jpeg");
            response.getOutputStream().write(this.fileInfoService.previewImage(fileId));
        } catch (IOException e) {
            throw new ServiceException(CoreExceptionEnum.SERVICE_ERROR);
        }
        return null;
    }

    /**
     * 下载文件
     *
     * @param fileId:   文件id
     * @param response: 相应
     * @throws Exception：异常
     */
    @RequestMapping(path = "/{fileId}.download", method = RequestMethod.GET)
    @ResponseBody
    public void download(@PathVariable String fileId, HttpServletResponse response) throws Exception {
        FileInfo fileInfo = this.fileInfoService.getById(fileId);
        if (fileInfo == null) {
            buildResponse(response, "文件不存在");
            return;
        }
        String fileName = fileInfo.getFileName();
        String filePath = fileInfo.getFilePath();
        try {
            File file = this.fileInfoService.downFile(filePath);
            if (file == null || !file.exists()) {
                buildResponse(response, "文件不存在");
                return;
            }
            response.reset();
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment;filename=" + new String(fileName.getBytes(), "ISO8859-1"));
            OutputStream fileOut = response.getOutputStream();
            fileOut.write(Files.readAllBytes(Paths.get(file.getAbsolutePath())));
            fileOut.flush();
        } catch (Exception ex) {
            ex.printStackTrace();
            buildResponse(response, "导出异常，" + ex.getMessage());
        }
    }

    /**
     * 删除接口
     *
     * @return 操作结果
     */
    @RequestMapping("/delete")
    @ResponseBody
    public ResponseData delete(@RequestParam("attachId") Long attachId) {
        return this.sysFileBusinessService.delete(attachId);
    }

    /**
     * 根据文件id删除
     *
     * @param fileId：文件id
     * @return 结果
     */
    @RequestMapping("/deleteFileById")
    @ResponseBody
    public ResponseData deleteByFileId(@RequestParam("fileId") String fileId, @RequestParam(value = "type", required = false) String type) {
        return this.fileInfoService.deleteByFileId(fileId, type);
    }

    /**
     * 查询列表
     *
     * @return 列表数据
     */
    @ResponseBody
    @RequestMapping("/list")
    public List<SysFileBusinessResult> list(@RequestParam("busSign") String busSign, @RequestParam("busId") Long busId) {
        return this.sysFileBusinessService.getAttach(busSign, busId);
    }

    /**
     * 根据业务标识和业务id获取附件列表
     *
     * @param busSign：业务标识
     * @param busId：业务id
     * @return 附件列表
     */
    @RequestMapping("/detail")
    @ResponseBody
    public ResponseData detail(@RequestParam("busSign") String busSign, @RequestParam("busId") Long busId) {
        List<SysFileBusinessResult> resultList = this.sysFileBusinessService.getAttach(busSign, busId);
        if (resultList != null && resultList.size() > 0) {
            return ResponseData.success(resultList.get(0));
        }
        return ResponseData.error("为获取数据");
    }

    /**
     * 根据附件id获取附件
     *
     * @param busSign：业务标识
     * @param busId：业务id
     * @param fileId：附件id
     * @return 附件对象
     */
    @RequestMapping("/detailByFileId")
    @ResponseBody
    public ResponseData detail(@RequestParam("busSign") String busSign, @RequestParam("busId") Long busId, @RequestParam("fileId") String fileId) {
        SysFileBusinessResult result = this.sysFileBusinessService.getAttach(busSign, busId, fileId);
        if (result != null) {
            return ResponseData.success();
        }
        return ResponseData.error("为获取数据");
    }

    /**
     * 根据关系id获取附件
     *
     * @param id：关系id
     * @return 附件对象
     */
    @RequestMapping("/detailById")
    @ResponseBody
    public ResponseData detail(@RequestParam("id") Long id) {
        SysFileBusinessResult result = this.sysFileBusinessService.getAttach(id);
        if (result != null) {
            return ResponseData.success();
        }
        return ResponseData.error("为获取数据");
    }

    @RequestMapping("/submitDemo")
    @ResponseBody
    public ResponseData submitDemo(HttpServletRequest request) {
        String attachFile = request.getParameter("attachFile");
        Long busId = ToolUtil.toLong(request.getParameter("busId"), 0L);
        this.sysFileBusinessService.saveAttach(attachFile, busId);
        return ResponseData.success();
    }

    /**
     * 保存附件关系
     *
     * @param busSign：业务标识
     * @param busId:                业务id
     * @param fileIds：附件id
     * @param deleteFileIds：删除的附件id
     * @return 结果
     */
    @RequestMapping("/saveRelation")
    @ResponseBody
    public ResponseData saveRelation(@RequestParam(value = "busSign") String busSign, @RequestParam(value = "busId") Long busId, @RequestParam(value = "fileIds") String fileIds, @RequestParam(value = "deleteFileIds") String deleteFileIds) {
        return this.sysFileBusinessService.save(busSign, busId, fileIds, deleteFileIds);
    }

    /**
     * 错误返回结果
     *
     * @param response: 响应
     * @param s：结果
     * @throws IOException 异常
     */
    private void buildResponse(HttpServletResponse response, String s) throws IOException {
        Map<String, String> resMap = new HashMap<>(0);
        resMap.put("code", "405");
        resMap.put("message", s);
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json; charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.write(JSONUtil.toJsonStr(resMap));
        writer.flush();
        writer.close();
    }


    /**
     * 下载文件
     *
     * @param fileIds: 文件id
     * @param response
     * @throws Exception
     */
    @RequestMapping(path = "/checkZip", method = RequestMethod.GET)
    @ResponseBody
    public void checkZip(String fileIds, HttpServletResponse response) throws Exception {
        if (StringUtil.isEmpty(fileIds)) {
            buildResponse(response, "文件不存在");
            return;
        }
        String[] ids = fileIds.split(",");
        List<File> list = new ArrayList<>();
        Map<String, String> names = new HashMap<>();
        for (String id : ids) {
            FileInfo fileInfo = this.fileInfoService.getById(id);
            if (fileInfo == null) {
                continue;
            }
            String filePath = fileInfo.getFilePath();
            File file = this.fileInfoService.downFile(filePath);
            names.put(file.getName(), fileInfo.getFileName());
            if (file == null || !file.exists()) {
                buildResponse(response, "文件不存在");
                return;
            }
            list.add(file);
        }
        try {
            if (list.size() > 0) {
                buildResponse(response, "");
                return;
            } else {
                buildResponse(response, "文件未找到");
                return;
            }

        } catch (Exception ex) {
            ex.printStackTrace();
            buildResponse(response, "导出异常，" + ex.getMessage());
            return;
        }
    }

    /**
     * 下载文件
     *
     * @param fileIds: 文件id
     * @param response
     * @throws Exception
     */
    @RequestMapping(path = "/downloadZip", method = RequestMethod.GET)
    @ResponseBody
    public void downloadZip(String fileIds, HttpServletResponse response) throws Exception {
        if (StringUtil.isEmpty(fileIds)) {
            return;
        }
        String[] ids = fileIds.split(",");
        List<File> list = new ArrayList<>();
        Map<String, String> names = new HashMap<>();
        for (String id : ids) {
            FileInfo fileInfo = this.fileInfoService.getById(id);
            if (fileInfo == null) {
                continue;
            }
            String filePath = fileInfo.getFilePath();
            File file = this.fileInfoService.downFile(filePath);
            names.put(file.getName(), fileInfo.getFileName());
            if (file == null || !file.exists()) {
                buildResponse(response, "文件不存在");
                return;
            }
            list.add(file);
        }
        try {
            if (list.size() > 0) {
                toZip(list, names, response);
            } else {
                buildResponse(response, "文件未找到");
                return;
            }

        } catch (Exception ex) {
            ex.printStackTrace();
            buildResponse(response, "导出异常，" + ex.getMessage());
            return;
        }
    }

    private void toZip(List<File> srcFiles, Map<String, String> names, HttpServletResponse response) {
//        long start = System.currentTimeMillis();

        ZipOutputStream zos = null;
        try {
            response.reset();
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment;filename=" + new String("制度.zip".getBytes(), "ISO8859-1"));//ISO8859-1
            OutputStream out = response.getOutputStream();
            zos = new ZipOutputStream(out);
            for (File srcFile : srcFiles) {
                byte[] buf = new byte[1024];
                String filename = StringUtil.isEmpty(names.get(srcFile.getName())) ? srcFile.getName() : names.get(srcFile.getName());
                zos.putNextEntry(new ZipEntry(formateFileName(filename)));
                int len;
                FileInputStream in = new FileInputStream(srcFile);
                while ((len = in.read(buf)) != -1) {
                    zos.write(buf, 0, len);
                }
                zos.closeEntry();
                in.close();
            }
//            long end = System.currentTimeMillis();
//            System.out.println("压缩完成，耗时：" + (end - start) + " ms");
        } catch (Exception e) {
            throw new RuntimeException("zip error from ZipUtils", e);
        } finally {
            if (zos != null) {
                try {
                    zos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private String formateFileName(String urlPrefix) {
        if (urlPrefix.indexOf("\\") >= 0) {
            return urlPrefix.substring(urlPrefix.lastIndexOf("\\") + 1, urlPrefix.length());
        }
        if (urlPrefix.indexOf("/") >= 0) {
            return urlPrefix.substring(urlPrefix.lastIndexOf("/") + 1, urlPrefix.length());
        }
        return urlPrefix;
    }

}


